import * as d3 from 'd3'
export class TreeChart {
    divId = ''
    data = []
    chart = {}
    i = 0
    color = d3.scaleOrdinal(d3.schemeCategory10)

    constructor (divId) {
      this.divId = divId
    }

    draw () {
      this.initChart()
      this.initLayout()
    }

    initChart () {
      this.chart.padding = {
        left: 20,
        right: 50,
        top: 50,
        bottom: 20
      }
      this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
          this.chart.padding.top -
          this.chart.padding.bottom
      this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
          this.chart.padding.left -
          this.chart.padding.right

      this.chart.svg = d3
        .select('#' + this.divId)
        .append('svg')
        .attr('width', this.chart.divWidth +
            this.chart.padding.left +
            this.chart.padding.right
        )
        .attr('height', this.chart.divHeight +
            this.chart.padding.top +
            this.chart.padding.bottom
        )
        .attr('class', 'svg_chart')
    }

    initLayout () {
      let tree = d3.tree()
        .size([this.chart.divWidth, this.chart.divHeight])

      let root = d3.hierarchy(this.data, d => d.children)
      this.rootData = tree(root)
      root._x = this.chart.divWidth / 2
      root._y = this.chart.padding.top
      this.drawTree(root)
    }

    drawTree (source) {
      this.drawNode(source)
      this.drawLink(source)
    }

    drawNode (source) {
      let nodes = this.rootData.descendants()
      nodes.forEach(d => {
        d.y = d.depth * 180 + this.chart.padding.top
      })

      //  ***********节点绘制*********
      let node = this.chart.svg.selectAll('g.node')
        .data(nodes, d => {
          return d.id || (d.id = ++this.i)
        })
      // ********新增加的节点*********
      let nodeEnter = node.enter()
        .append('g')
        .attr('class', 'node')
        .attr('transform', function (d) {
          return 'translate(' + source._x + ',' + source._y + ')'
        })
        .on('click', d => {
          if (d.children) {
            d._children = d.children
            d.children = null
          } else {
            d.children = d._children
            d._children = null
          }
          this.drawTree(d)
        })

      nodeEnter.append('circle')
        .attr('class', 'node')
        .attr('r', 5)
        .style('fill', 'red')

      nodeEnter.append('text')
        .attr('dy', '2em')
        .style('font-size', 8)
        .attr('text-anchor', 'middle')
        .text(function (d) {
          return d.data.name
        })
        .style('fill-opacity', 1)

      // ************新增节点动画过渡*********
      let nodeUpdate = nodeEnter.merge(node)

      nodeUpdate.transition()
        .duration(750)
        .attr('transform', function (d) {
          return 'translate(' + d.x + ',' + d.y + ')'
        })

      nodeUpdate.select('node.circle')
        .style('fill', '#fff')
        .attr('r', 5)

      // ***********删除的节点********
      let nodeExit = node.exit().transition()
        .duration(750)
        .attr('transform', function (d) {
          return 'translate(' + source.x + ',' + source.y + ')'
        })
        .remove()

      nodeExit.selectAll('node.circle')
        .attr('r', 1e-6)

      nodeExit.selectAll('node.text')
        .style('fill-opacity', 1e-6)

      // ************保存当前节点的坐标***********
      nodes.forEach(function (d) {
        d._x = d.x
        d._y = d.y
      })
    }

    drawLink (source) {
      let links = this.rootData.descendants().slice(1)

      //  ***********连线绘制*********
      let link = this.chart.svg.selectAll('path.link')
        .data(links, function (d) {
          return d.id
        })
      // **************新增的连线************
      let linkEnter = link.enter().insert('path', 'g')
        .attr('class', 'link')
        .style('fill', 'none')
        .style('stroke', '#ccc')
        .style('stroke-width', 1)
        .attr('d', function (d) {
          var o = {
            x: source._x,
            y: source._y
          }
          return diagonal(o, o)
        })

      let linkUpdate = linkEnter.merge(link)
      // ***********连线动画过渡*******
      linkUpdate.transition()
        .duration(750)
        .attr('d', function (d) {
          return diagonal(d, d.parent)
        })
      // ************删除的连线************
      link.exit().transition()
        .duration(750)
        .attr('d', function (d) {
          var o = {
            x: source.x,
            y: source.y
          }
          return diagonal(o, o)
        })
        .remove()
      function diagonal (s, d) {
        let path = `M ${s.x} ${s.y}
                C ${s.x} ${(s.y + d.y) / 2},
                  ${d.x} ${(s.y + d.y) / 2},
                  ${d.x} ${d.y}`
        return path
      }
    }
}
